# 1. 加载和执行
- 多数浏览器使用单一进程来处理用户界面(UI)刷新和javascript脚本执行,所以同一时刻只能做一件事。这是页面生存周期中的必要环节,因为脚本执行中可能会修改页面内容。
- 以下代码中file1.js会先下载再执行。然后file2.js下载再执行。最后file3.js下载再执行。
<head>
<script src='file1.js'></script>
<script src='file2.js'></script>
<script src='file3.js'></script>
</head>
1
2
3
4
5
2
3
4
5
- script标签中async与defer相同点是采用并行下载,在下载过程中不会产生阻塞。区别在于执行时机,async是加载完成后自动执行,而defer需要等待页面完成后执行(onload事件被触发前执行),defer属性尽当src属性声明时才生效。
<head>
<script src='file1.js' defer></script>
</head>
1
2
3
2
3
- 动态脚本元素
function loadscript(url,callback){
var script=document.createElement('script');
script.type='text/javascript';
if(script.readyState){
//IE
script.onreadystatechange=function(){
if(script.readyState=='loaded'||script.readyState=='complete'){
script.onreadystatechange=null;
callback();
}else{
//其他浏览器
script.onload=function(){
callback();
}
}
script.src=url;
document.getElementsByTagName('head')[0].appendChild(script);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
文件在该元素被添加到页面时开始下载。这种技术重点在于:无论在何时启动下载,文件的下载和执行过程不会阻塞页面其他进程。动态脚本加载凭借着它在跨浏览器兼容性和易用的优势,成为最通用的无阻塞加载的解决方案。
- XMLHttpRequest脚本注入
var xhr=new XMLHttpRequest();
xhr.open=('get','file.js',true);
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
if(xhr.status>=200&&xhr.status<300||xhr.status==304){
//304意味着是从缓存读取
var script=document.createElement('script');
script.type='text/javascript';
script.text=xhr.responseText;
document.body.appendChild(script);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
一旦新创建<script>元素被添加到页面,代码就会立刻执行然后准备就绪。 这种方法的有点是你可以js但是不立即执行。可以推迟到你准备好的时候。
- LazyLoad (opens new window)类库 LazyLoad是loadscript()函数的增强版。
LazyLoad.js(['first.js','second.js'],function(){
//...
})
1
2
3
2
3
每次下载仍然是一个独立的http请求,而且回调函数会等待所有文件都下载完成后才会执行。
# 总结
- 将所有<script>标签放到body闭合标签前,确保脚本执行前已经完成了渲染。
- 合并脚本。页面中的script标签越少,加载就越快,响应也更迅速。
- 有多种无阻塞下载js的方法:
- 使用<script>标签的defer属性。
- 使用动态创建的<script>标签下载并执行代码。
- 使用XHR对象下载js代码并注入页面中。